//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.eResearch.Subscriber
{
    using System;
    using System.Globalization;
    using Microsoft.Research.eResearch.Blackboard.Common;
    using Microsoft.Research.eResearch.Common.Eventing;
    using Microsoft.Research.eResearch.Common.Logging;
    using Microsoft.Research.eResearch.Common.Reflection;
    using Microsoft.Research.eResearch.Subscriber.Interfaces;

    /// <summary>
    /// Provides an easy-to-use API that subscribers can use to notify the Blackboard of its
    /// subscription profile and receive notifications of new blackboard messages.
    /// </summary>
    public class BlackboardSubscriber : ILoggable
    {
        /// <summary>
        /// Address of the subscription receiver host.
        /// </summary>
        private Uri returnAddress;

        /// <summary>
        /// Instance of the message sender.
        /// </summary>
        private INotificationMessageReceiver notificationMessageReceiver;

        /// <summary>
        /// Instance of the subscription receiver.
        /// </summary>
        private INotificationSubscriptionSender notificationSubscriptionSender;

        /// <summary>
        /// Last subscription profile that was received.
        /// </summary>
        private SubscriptionProfile lastSubscriptionProfile = new SubscriptionProfile();

        /// <summary>
        /// Initializes a new instance of the <see cref="BlackboardSubscriber"/> class.
        /// Creates instances of the types defined in the configuration file with keys
        /// "INotificationMessageReceiver" and "INotificationSubscriptionSender".
        /// </summary>
        public BlackboardSubscriber()
        {
            notificationMessageReceiver = ReflectionHelper.CreateInstance<INotificationMessageReceiver>("INotificationMessageReceiver");
            notificationSubscriptionSender = ReflectionHelper.CreateInstance<INotificationSubscriptionSender>("INotificationSubscriptionSender");
            notificationMessageReceiver.BlackboardMessageReceived += OnBlackboardMessageReceived;
        }

        /// <summary>
        /// Occurs when a new blackboard message is received.
        /// </summary>
        public event EventHandler<BlackboardMessageReceivedEventArgs> BlackboardMessageReceived;

        /// <summary>
        /// Raised when a log message is received.
        /// </summary>
        public event EventHandler<LogEventArgs> LogMessageReceived;

        /// <summary>
        /// Gets the last subscription profile that was sent to the Blackboard.
        /// </summary>
        /// <value>The last subscription profile.</value>
        public SubscriptionProfile LastSubscriptionProfile
        {
            get { return lastSubscriptionProfile; }
            
            // Save a copy
            private set { lastSubscriptionProfile = new SubscriptionProfile(value); }
        }

        /// <summary>
        /// Begins listening for new blackboard messages.
        /// </summary>
        public void Start()
        {
            if (notificationMessageReceiver != null)
            {
                Log("Attempting to start...");
                returnAddress = notificationMessageReceiver.Start();
            }
        } 

        /// <summary>
        /// Stops listening for new blackboard messages.
        /// </summary>
        public void Stop()
        {
            if (notificationSubscriptionSender != null)
            {
                Log("Attempting to unsubscribe.");
                notificationSubscriptionSender.Unsubscribe(returnAddress);
            }

            if (notificationMessageReceiver != null)
            {
                Log("Attempting to stop...");
                notificationMessageReceiver.Stop();
            }
        } 

        /// <summary>
        /// Sends the specified subscription profile to the Blackboard.  This method
        /// may also be called to change (update) to a new subscription profile.
        /// </summary>
        /// <param name="profile">The profile.</param>
        public void Subscribe(SubscriptionProfile profile)
        {
            if (notificationSubscriptionSender != null)
            {
                Log("Attempting to subscribe...");
                notificationSubscriptionSender.Subscribe(returnAddress, profile);
            }

            this.LastSubscriptionProfile = profile;
        } 

        /// <summary>
        /// Raises the BlackboardMessageReceived event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.eResearch.Subscriber.Interfaces.BlackboardMessageReceivedEventArgs"/> instance containing the event data.</param>
        private void OnBlackboardMessageReceived(object sender, BlackboardMessageReceivedEventArgs e)
        {
            this.BlackboardMessageReceived.Fire(this, e);
        }

        /// <summary>
        /// Raises the <see cref="E:LogMessageReceived"/> event.
        /// </summary>
        /// <param name="args">The <see cref="Microsoft.Research.eResearch.Common.Logging.LogEventArgs"/> instance containing the event data.</param>
        private void OnLogMessageReceived(LogEventArgs args)
        {
            this.LogMessageReceived.Fire(this, args);
        }

        /// <summary>
        /// Log the message.
        /// </summary>
        /// <param name="message">Message text to be logged.</param>
        private void Log(string message)
        {
            OnLogMessageReceived(new LogEventArgs("Debug", String.Format(CultureInfo.CurrentUICulture, "BlackboardSubscriber: {0}", message)));
        }
    }
}
